from collections import namedtuple
import csv
import re
import sys

from decode1_gen import macro_name

Signal = namedtuple('Signal', ['name', 'width'])

re_signal = re.compile(r'(\w+)(\[(\d+):(\d+)\])?')

def parse(table_file):
    global instr_class_list
    global output_signal_list
    global expr_table
    reader = csv.reader(table_file)
    instr_class_list = next(reader)[1:] # read first row, discard first cell
    output_signal_list = []
    expr_table = []
    for values in reader:
        match = re_signal.match(values[0])
        if match.group(2):
            width = int(match.group(3))-int(match.group(4))+1
        else:
            width = 1
        output_signal_list.append(Signal(match.group(1), width))
        expr_table.append(values[1:])

def main():
    (source_fpath,) = sys.argv[1:]
    with open(source_fpath, 'r') as f:
        parse(f)
    with open('instruction_decoder2.v', 'w') as f:
        f.write('`include "instructions.vh"\n')
        f.write('module instruction_decoder2(i, i_instr_class, %s);\n' %
                ', '.join(map(lambda signal: signal.name, output_signal_list)))
        f.write('/* verilator lint_off UNUSED */ input [31:0] i; /* verilator lint_on UNUSED */\n')
        f.write('input [`NUM_INSTR-1:0] i_instr_class;\n')
        for signal in output_signal_list:
            f.write('output reg [%d:0] %s;\n' % (signal.width-1, signal.name))
        f.write('`include "instruction_decoder2_helper.vh"\n')
        f.write('always @* begin\n')
        f.write("  case (1'b1)\n")
        for class_index, instr_class in enumerate(instr_class_list):
            f.write("    i_instr_class[`%s]: begin\n" % macro_name(instr_class))
            for signal_index, signal in enumerate(output_signal_list):
                expr = expr_table[signal_index][class_index]
                if expr == '':
                    expr = "%d'bx" % signal.width
                f.write("      %s = %s;\n" % (signal.name, expr))
            f.write('    end\n')
        # default case (should not happen)
        f.write('    default: begin\n')
        for s in output_signal_list:
            f.write("      %s = %d'bx;\n" % (s.name, s.width))
        f.write('    end\n')
        f.write('  endcase\n')
        f.write('end\n')
        f.write('endmodule\n')

if __name__ == "__main__":
    main()
